var waterfall = require('async').waterfall;
var pomelo = require('pomelo');
var eachLimit = require('async').eachLimit;
var each = require('async').each;

var async = require('async');

var log = console.log;

var consts = require('../../consts/consts');
var utils = require('../../util/utils');
var userDao = require('../../dao/userDao');  // mysqlClient

var playerUtil = require('../util/player');

var redisUser = pomelo.app.get('redisUser');  // redisClient

var playerLogger = require('pomelo-logger').getLogger('player', pomelo.app.serverId).info;

var exceptionLogger = require('pomelo-logger').getLogger('exception', pomelo.app.serverId).info;

var getYuan = utils.getYuan;

var mysql = userDao;
var client = redisUser;

function PlayerManager(roomObj) {
    this.roomObj = roomObj;
    this.playerData = {};
    this.playerNum = 0;

    // 机器人信息同样放在playerData中，没有单独的robotData
    // robotNum++的时候，同样playerNum++
    this.robotNum = 0; // 机器人数量
    this.robotList = []; // 机器人列表

    this.bidData = {};  // 下注信息容器
}

// 根据id获取用户的信息
// in: playerId
// out: {name, coin, score, roundCount}
PlayerManager.prototype.getPlayerData = function (playerId) {
    console.log('PlayerManage.getPlayerData ---------------');
    var player, ret;

    if (this.playerData[playerId]) {
        player = this.playerData[playerId];
        ret = {
            playerId,
            name: player.playerName,
            coin: player.coin,
            score: player.score,
            roundCount: player.roundCount
        };
    }

    return ret || { name: 'guest', coin: 0, score: 0, roundCount: 0 };
};

// 返回用户列表，从内存中获取数据
// out: [{playerId, name, coin}, ...]
PlayerManager.prototype.getPlayerList = function () {
    console.log('PlayerManager.getPlayerList caught >>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
    var playerData = this.playerData;

    function sortByCoin(p1, p2) {
        return p2.coin - p1.coin;
    }

    var list = [], playerId;

    for (playerId in playerData) {
        list.push({
            playerId,
            name: playerData[playerId].playerName,
            coin: playerData[playerId].coin
        });
    }
    // list.sort(sortByCoin);

    console.log(list);
    return list;
};

/**
 * 用户管理添加用户
 * 1.查询到player信息 2.写到内存里面 3. 写到redis里面
 * 1.1.从redis里面查询 1.2.查不到的话从mysql里面查询，并且写到redis里面
 * in: data: {serverId, playerId, token, gameId, playerName, isRobot, ip}
 */
PlayerManager.prototype.addPlayer = function (data, callback) {
    console.log('PlayerManage.addPlayer caught ----------------');
    var self = this;
    var playerId = data.playerId;

    var players = this.playerData;
    var player = null;

    // 如果还没有删掉用户数据，就更新用户数据
    // if(players[playerId]) {
    //     delete players[playerId];
    // }
    // 自然会更新

    // console.log(data);
    // 查询并存储用户信息
    playerUtil.playerLogin(data, function (err, rel) {
        if (err) {
            console.log(err);
            callback(err);
        }
        else {
            var index = self.robotList.indexOf(playerId);

            if (index > -1) {
                self.robotList.splice(index, 1);
                self.robotNum--;
            }
            player = rel;
            players[playerId] = player;
            player.isRobot = false;

            // log(players);

            // 如果在掉线玩家名单里，就删掉
            var idx = self.roomObj.offlinePlayer.indexOf(playerId);
            if (idx > -1) {
                self.roomObj.offlinePlayer.splice(idx, 1);
            }

            self.playerNum++;

            callback(null);
        }
    });

};

// player num in the room
PlayerManager.prototype.getPlayerNum = function () {
    return this.playerNum;
};

// 人数无上限？  废弃或更改 MAX_MEMBER_NUM
PlayerManager.prototype.isRoomFull = function () {
    return this.playerNum >= consts.ROOM.MAX_MEMBER_NUM;
};

PlayerManager.prototype.isPlayerInRoom = function (playerId) {
    var players = this.playerData;
    // if (players[playerId]) {
    //     return true;
    // }
    // return false;
    return players[playerId] ? true : false;
};

PlayerManager.prototype.getPlayerNameById = function (playerId) {
    var players = this.playerData;
    return players[playerId].playerName || '';
};

PlayerManager.prototype.isRobotPlayer = function (playerObj) {
    return playerObj.isRobot;
};

// PlayerManager.prototype.isEmptyPosition = function (playerObj) {
//     return (playerObj.playerName === consts.ROOM.PLAYER_NAME_NONE);
// };

PlayerManager.prototype.getRealPlayerNum = function () {
    var tmpNum = 0;
    var players = this.playerData;
    for (var i in players) {
        var o = players[i];
        var isRobot = this.isRobotPlayer(o);
        // var isEmpty = this.isEmptyPosition(o);
        if (!isRobot) {
        // if (!isRobot && !isEmpty) {
            tmpNum++;
        }
    }
    return tmpNum;
};

// 玩家离开
// 立即从内存中删掉，但是redis中要缓存30分钟
// 还需要从channel中删掉
// 但是庄家掉线不能直接删掉
PlayerManager.prototype.kickPlayer = function (data) {
    var players = this.playerData;
    var playerId = data.playerId;
    var room = this.roomObj;
    if (room.checkGameStatus('xiazhu') && this.bidData[playerId]) {
        // 如果是下注时间并且已经下注，不能删掉，否则无法结算
        // TODO: 如果转到开牌时间了，但是还没有完成结算和记录，也还是不能删掉用户信息
        room.offlinePlayer.push(playerId);
    }
    else {
        // 否则可以直接删掉
        delete players[playerId];

        var key = 'onlineGameUser';
        client.hdel(key, playerId, function (err, rel) {
            if (err) {
                log(err);
                throw new Error('redis err:', err);
            }
            else {
                log('玩家%s已经退出游戏 %s', playerId, room.gameId);
            }
        });

        // 玩家数量记录减少
        this.playerNum--;
    }

    return true;
};

PlayerManager.prototype.kickPlayerById = function (playerId) {
    console.log('PlayerManager.kickPlayerById caught ---------------------------');

    var players = this.playerData;
    delete players[playerId];

    this.playerNum--;

    return true;
};

// 结算，更新玩家金钱
// 下注：0： 庄赢；1：闲赢；2：平局；3：庄对子；4：闲对子；5：都是对子；6：大；7：小；
// result = 000;  输赢，对子，大小
// 要添加税收。问题： 税收是收所有押对的，还是收最终赚的钱的？
// 如果所有押对的，那么如果押对的赚的少于押错的赔的，难道还要多赔钱？ 所以只能是如果最终是赚钱的，才收税，收赚的钱的税，而不是押对的注的税。
// 如果把押上的全都算已经给庄家了，那么可以把所有赢的都收税，这时不再算最终收入，只管每个位置是否押对
// 税收2%

// 只计算结果，不记录结果
PlayerManager.prototype.calcResultOnly = function (odds, cb) {
    console.log('PlayerManager.calcResultNew caught     >>>>>>>>>>>>>>>>>>>>>>');
    // log('所有的下注记录 this.bidData：', this.bidData);

    // var self = this;
    var bidData = this.bidData;
    var playerData = this.playerData;
    var coinChange = {};

    var playerId;
    var room = this.roomObj;

    var roundRel = {
        userCount: 0,  // 总玩家数量
        robotCount: 0,
        bidCoin: 0,  // 总下注数额
        tax: 0,  // 总税收
        platformProfit: 0  // 系统总收入
    };

    var bidRecord,  // 下注记录
        pos,  // 位置
        bidCoin,  // 该位置的所有投注
        coinGainSum,  // 此人赚的所有钱
        bidCoinSum,  // 此人的所有投注
        bankerReturn = 0;  // 庄家返还

    var tax = consts.ROOM.TAX,
        taxCoin,
        coinChangeNum;

    // log('检查房间设置');
    if (room.config) {
        if (parseInt(room.config.TAX) > -1) {
            // log('已配置税率：', room.config.TAX);
            tax = parseInt(room.config.TAX);
        }
    }
    // log('最终税收：', tax);

    var isRobot,
        robotSum = 0,  // 机器人的总输赢
        sysGain = 0;  // 系统总共赚的

    // 计算所有非庄家用户的改变量
    for (playerId in bidData) {

        // console.log('玩家金钱：', playerData[playerId].coin);

        // 初始化用到的变量
        bidCoinSum = 0;
        coinGainSum = 0;
        taxCoin = 0;
        coinChangeNum = 0;
        // 每个用户
        // playerId = k;

        isRobot = playerData[playerId].isRobot;

        if (!isRobot) {
            // 本局下注真实用户数目
            roundRel.userCount++;
        }
        else {
            // 本局下注机器人数目
            roundRel.robotCount++;
        }

        // 当前用户下注记录
        bidRecord = bidData[playerId];
        // bidRecord = {0: 123, 3: 123, ...}

        for (pos in bidRecord) {
            // 下注记录的每个位置
            bidCoin = parseInt(bidRecord[pos]);

            // 本局总下注额
            // 机器人下的注也不计入
            if (!isRobot) {
                roundRel.bidCoin += bidCoin;
            }

            // 押庄闲的如果平局的话，返还下注            
            if ((parseInt(pos) === 2 || parseInt(pos) === 0) && odds[pos] === 1) {
                playerData[playerId].coin += bidCoin;  // 直接返回，当做没有下注
            }
            else {
                // TODO: 要考虑是否应该把下到庄闲的也算进下注总额中。
                bidCoinSum += bidCoin;  // 下注总额
                coinGainSum += bidCoin * odds[pos];  // 赚钱总额
            }
        }

        if (coinGainSum > bidCoinSum) {
            if (tax === 0) {
                taxCoin = 0;
            }
            else {
                // 税 = 净赚 * 税率
                taxCoin = Math.floor((coinGainSum - bidCoinSum) * tax / 100);
            }
        }

        // 本局玩家金钱改变 = 赚的钱 - 下的注 - 付的税
        coinChangeNum = coinGainSum - bidCoinSum - taxCoin;

        // log('12222222222', coinChangeNum, typeof coinChangeNum, bidCoinSum, typeof bidCoinSum, playerData[playerId].coin, typeof playerData[playerId].coin);

        // 此刻金钱改变 = 赚的钱 - 下的注 - 付的税 + 下的注
        playerData[playerId].coin += (coinChangeNum + bidCoinSum);

        coinChange[playerId] = {
            playerId,
            bidRecord,
            taxCoin,
            coinChange: coinChangeNum,
            coin: playerData[playerId].coin
        };
        bankerReturn += (coinChangeNum + taxCoin);

        if (isRobot) {
            // log('robot: ', playerId);
            robotSum += (coinChangeNum + taxCoin);
            if (room.existsBanker()) {
                // 系统赚机器人赚的所有的(只有有真人坐庄，机器人赚的钱才是系统的)
                sysGain += (coinChangeNum + taxCoin);
            }
        }
        else {
            // 本局总税收(只有对真人收的税才是真的税)
            roundRel.tax += taxCoin;
            // 如果玩家坐庄，系统只赚税
            // 如果系统坐庄，系统赚玩家亏的
            if (room.existsBanker()) {
                sysGain += taxCoin;
            }
            else {
                sysGain -= coinChangeNum;
            }
        }
    }

    log('机器人总结果： ', robotSum);

    // log('coinChange ////////////////////////////');
    // // log(odds);
    // log(coinChange);

    // 暂时设置下注用户数为1来测试机器人    
    // roundRel.userCount = 1;

    // 存在庄家且存在下注，计算庄家结果
    if (room.existsBanker() && (roundRel.userCount || roundRel.robotCount)) {
        console.log('calcResult Banker >>>>>>>>>>>>>>>>>>>>>>>>');
        var bankerId = room.curBanker;
        var bankerTax;
        var bankerGain;

        if (!coinChange.banker) {
            coinChange.banker = {
                playerId: 'banker',
                coinChange: 0,
                taxCoin: 0
            };
        }
        if (bankerReturn > 0) {
            // 庄家是赔钱的
            playerData[bankerId].coin -= bankerReturn;
            coinChange.banker.coinChange -= bankerReturn;
            // coinChange.banker.taxCoin = 0;
        }
        else if (bankerReturn < 0) {
            // 庄家是赚钱的

            bankerTax = ((-bankerReturn) * tax / 100);
            bankerGain = (-bankerReturn) - bankerTax;

            coinChange.banker.taxCoin = bankerTax;
            coinChange.banker.coinChange = bankerGain;

            playerData[bankerId].coin += bankerGain;

            sysGain += bankerTax;

            // 本局总税收
            roundRel.tax += bankerTax;

        }
        // else {
        //     // 庄家不赚不赔
        //     coinChange.banker.coinChange = 0;
        //     coinChange.banker.taxCoin = 0;
        // }
        coinChange.banker.coin = playerData[bankerId].coin;

        // 更新庄的分数
        room.curBankerScore += coinChange.banker.coinChange;
        coinChange.banker.score = room.curBankerScore;
        coinChange.banker.round = room.curBankerRound;
    }
    else if (room.existsBanker() && !(roundRel.userCount || roundRel.robotCount)) {
        // 有人坐庄却无人下注
        coinChange.banker = {
            playerId: 'banker',
            coinChange: 0,
            taxCoin: 0
        };
        coinChange.banker.coin = playerData[room.curBanker].coin;
        coinChange.banker.score = room.curBankerScore;
        coinChange.banker.round = room.curBankerRound;
    }

    if (coinChange.banker) {
        // log('banker结果：', coinChange.banker);

        if (!coinChange[room.curBanker]) {
            coinChange[room.curBanker] = {};
            coinChange[room.curBanker].playerId = room.curBanker;
            coinChange[room.curBanker].coin = coinChange.banker.coin;
            coinChange[room.curBanker].taxCoin = coinChange.banker.taxCoin;
            coinChange[room.curBanker].coinChange = coinChange.banker.coinChange;
        }

        // log('庄家结果：', coinChange[bankerId]);
    }

    // 本局系统总赚钱
    roundRel.platformProfit = sysGain;

    log('此局系统赚钱：', sysGain);
    // log('最终结算结果 coinChange： ', coinChange);

    this.recordResultOnly(coinChange, roundRel, cb);
};

//只记录结果
PlayerManager.prototype.recordResultOnly = function (coinChange, roundRel, cb) {

    log('记录此局结果');

    // log(roundRel);

    var self = this;

    var room = this.roomObj;
    var playerData = this.playerData;

    // 如果没有庄也无人下注，那么就不记录这一局的结果
    if (!room.existsBanker() && !(roundRel.userCount || roundRel.robotCount)) {
        // 要返回coinChange 用于可能的庄家局数递增返回数据
        cb(null, coinChange);
        return;
    }

    var bankerId = room.curBanker || 0;
    var bankerName = bankerId > 0 ? playerData[bankerId].playerName : 'none';

    var gameId = room.gameId;
    var curCards = room.curRecCards;
    var curCardsStr = room.curCardsStr;

    log('当前的牌是：', curCards);

    // curCards = curCards.join('_').replace(/0x/g, '|').substring(1);
    // curCards = curCards.replace(/0x/g, '|').substring(1);

    // 首先插入牌局记录表，并通过返回值获取到新增的id
    var sql = 'INSERT INTO game_round (gameId, roomName, userId, userName, card, cardResult, userCount, bidCoin, tax, platformProfit, duration, addTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())';
    var args = [gameId, room.name, bankerId, bankerName, curCards, curCardsStr, roundRel.userCount, getYuan(roundRel.bidCoin), getYuan(roundRel.tax), getYuan(roundRel.platformProfit), room.xiaZhuTime];

    var insertId;

    var coinField = 'coin';

    mysql.query(sql, args, function (err, rows) {
        if (err) {
            exceptionLogger('calcResult', coinChange, err);
            cb(err, {});
            throw new Error('caught exception when calcResult in playerManager.js');
            // throw 当做 return 用
        }
        insertId = rows.insertId;

        log('roundId: ', insertId);
        log('记录的数量是：');
        var stCount = 0, stPlayerList = [];
        for (let st in coinChange) {
            stCount++;
            stPlayerList.push(coinChange[st].playerId);
        }
        log(stCount);
        log(stPlayerList.toString());
        
        eachLimit(coinChange, 3,
            function (p, callback) {
                // 不在特别识别庄家
                if (p.playerId === 'banker') {
                    return callback(null);
                }
                // log(p);
                var playerId = p.playerId === 'banker' ? room.curBanker : p.playerId;
                var player = playerData[playerId];
                var playerName = player.playerName;
                var isRobot = player.isRobot;

                // 把下注记录里的分转换为元                
                if (p.bidRecord && typeof (p.bidRecord) !== 'string') {
                    for (k in p.bidRecord) {
                        p.bidRecord[k] = getYuan(p.bidRecord[k]);
                    }
                }

                var bidRecord = JSON.stringify(p.bidRecord) || 'banker';

                delete p.bidRecord; // 删掉广播的下注记录
                // log('用户记录： ', p.playerId, p);

                var result = 0;

                if (p.coinChange > 0) {
                    result = 1;
                }
                else if (p.coinChange < 0) {
                    result = -1;
                }

                // if(isRobot) {
                //     callback(null);
                //     return;
                // }

                waterfall([
                    function (wcb) {
                        // 插入个人流水记录表
                        // 机器人的不再记录
                        if (isRobot) {
                            wcb(1);
                            return;
                        }
                        // log('mysql里面的: ', playerId);
                        var sql = 'insert into game_queue (gameId, userId, userName, bidRecord, coinChange, tax, result, roundId, addTime) values (?, ?, ?, ?, ?, ?, ?, ?, now())';
                        var args = [gameId, playerId, playerName, bidRecord, getYuan(p.coinChange), getYuan(p.taxCoin), result, insertId];
                        console.log('args >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
                        console.log(args);

                        mysql.query(sql, args, function (err, rows, field) {
                            if (err) {
                                wcb(err);
                            }
                            else {
                                wcb(null);
                            }
                        });
                    },
                    function (wcb) {
                        // 更新缓存的逻辑
                        /**
                         * 1.从 redis 中读取缓存，如果存在，证明在其它地方没有改变，那么就直接更新 redis
                         * 2.如果读不到，证明其它地方更新了 redis，从 mysql 中读取，更新 redis 和内存中的数据
                         * 3.从 redis 中读取数据，更新到内存中
                         */

                        client.hget(playerId, coinField, function (err, rel) {
                            if (err) {
                                wcb(err);
                                return;
                            }
                            if (rel !== null) {
                                // 没有更新，可直接使用
                                wcb(null, 0);
                            }
                            else {
                                // 其它地方更新了
                                var sql = 'SELECT (coin + (SELECT ifnull(sum(coinChange), 0) coinChange FROM game_queue WHERE userId = ? AND isDone = 0) ) as coin FROM game_user where userId = ?';
                                var args = [playerId, playerId];
                                mysql.query(sql, args, function (err, rows) {
                                    if (err) {
                                        log(err);
                                        return wcb(err);
                                    }
                                    // 暂时不重新设置机器人金钱
                                    // if(!rows[0]) {
                                    //     player.coin = player.coin;
                                    // }
                                    player.coin = rows[0].coin * 100;
                                    wcb(null, 1);
                                });
                            }
                        });
                    },
                    function (type, wcb) {
                        // 重新设置或者递增缓存
                        var coinKey = 'coin' + playerId;
                        type = 1;  // 不管如何，先都重新设置缓存
                        if (type) {
                            // 重新设置缓存
                            log('重新设置缓存', player.coin);
                            client.hset(playerId, coinField, getYuan(player.coin), function (err, rel) {
                                if (!err) {
                                    return wcb(null);
                                }
                                else {
                                    return wcb(err);
                                }
                            });
                        }
                        else {
                            log('递增缓存', getYuan(player.coin), p.coinChange);
                            client.incrby(coinKey, p.coinChange, function (err, rel) {
                                if (err) {
                                    wcb(err);
                                }
                                else {
                                    log('结算', coinKey, '改变了：', p.coinChange);
                                    wcb(null);
                                }
                            });
                        }
                    }
                ],
                    function (err) {
                        if (!err) {
                            return callback(null);
                        }

                        if (err === 1) {
                            callback(null);
                        }
                        else {
                            callback(err);
                        }
                    }
                );  // end of waterfall

            },
            function (err) {
                if (err) {
                    console.log(err);
                    cb(err, {});
                    exceptionLogger('calcResult', coinChange, err);
                    throw new Error('caught exception when calcResult in playerManager.js');
                }
                else {
                    // log(coinChange);
                    // log(playerData);
                    cb(null, coinChange);
                }
            });
    });
};


/**
 * 检查下注的玩家和机器人各自下注的位置
 * 玩家坐庄：机器人下注多的地方赢；系统或者机器人坐庄：玩家下注多的地方输
 * 平0，庄1，闲2
 */
PlayerManager.prototype.checkBidCount = function () {
    log('检查下注数量，决定输赢');
    // var self = this;

    var room = this.roomObj;

    var winnerObj = {
        0: '平局',
        1: '庄赢',
        2: '闲赢'
    };
    var retStr = room.retStr;
    var winner = parseInt(retStr.substring(0, 1));
    var corrWinner;

    if (winner === 0) {
        log('平局，不干扰');
        return true;
    }

    log('下注总数量........................');

    for (var k in room.robotBidCount) {
        // 把总下注统计中的机器人下注去掉，获得真实用户下注总计
        room.bidCount[k] -= room.robotBidCount[k];
    }
    log(room.bidCount);
    log(room.robotBidCount);

    // 下闲多： 2； 下庄多： 1
    var playerBidType = 1, robotBidType = 1;

    if (room.bidCount[0] > room.bidCount[2]) {
        // log('玩家：闲多');
        playerBidType = 2;
    }
    else if (room.bidCount[2] === room.bidCount[0]) {
        // log('玩家：相同');
        playerBidType = 0;
    }
    // else {
    //     log('玩家：庄多');
    // }

    if (room.robotBidCount[0] > room.robotBidCount[2]) {
        // log('机器人：闲多');
        robotBidType = 2;
    }
    else if (room.robotBidCount[2] === room.robotBidCount[0]) {
        // log('玩家：相同');
        robotBidType = 0;
    }
    // else {
    //     log('机器人：庄多');
    // }

    var banker = room.curBanker;
    var bankerType = 0;

    if (banker > 0) {
        bankerType = 1;
        log('玩家坐庄');
    }
    else {
        log('系统坐庄');
    }

    log('本局结果是', winnerObj[winner]);

    // key： 上庄类型 0：系统上庄，1：玩家上庄
    // 系统上庄，玩家下注少的地方赢

    if (bankerType) {
        // 玩家上庄，需要机器人下注多的地方赢
        if (robotBidType === 1) {
            // 机器人下庄多
            corrWinner = 1;  // 需要庄赢
        }
        else if (robotBidType === 0) {
            corrWinner = winner;
            log('机器人两边下注数量相同，结果不变！');
        }
        else {
            corrWinner = 2;
        }
    }
    else {
        // 系统上庄，需要玩家下注少的地方赢
        if (playerBidType === 1) {
            // 玩家下庄多
            corrWinner = 2;  // 需要闲赢
        }
        else if (playerBidType === 0) {
            corrWinner = winner;
            log('玩家两边下注数量相同，结果不变！');
        }
        else {
            corrWinner = 1;
        }
    }

    if (corrWinner === winner) {
        log('所需结果与自然结果相同，不做干扰！');
        return true;
    }
    else {
        return false;
    }

};

/**
 * 更改游戏结果，交换庄家和闲家的牌
 * room.curCards, room.retStr, room.curResultOdds, room.curCardsStr
 */
PlayerManager.prototype.changeCard = function () {
    log('交换玩家和庄家的牌');

    var self = this;

    var room = this.roomObj;

    log(room.curCards, room.retStr, room.curResultOdds, room.curCardsStr);
    var retStr = room.retStr;
    var curResultOdds = room.curResultOdds;
    var curCardsStr = room.curCardsStr;

    var obj = {};
    // 交换牌局
    obj.curCards = [room.curCards[1], room.curCards[0]];
    // 改变结果
    obj.retStr = '';

    for (var i = 0; i < 3; i++) {
        if (parseInt(retStr.charAt(i)) === 1) {
            obj.retStr += '2';
        }
        else if (parseInt(retStr.charAt(i)) === 2) {
            obj.retStr += '1';
        }
        else {
            obj.retStr += retStr.charAt(i);
        }
    }
    obj.retStr += retStr.charAt(3);

    // 改变赔率
    // 0闲 1和 2庄 3大 4闲天王 5闲对子 6庄对子 7庄天王 8小
    // 和还是和，大小还是大小，其它的对调
    obj.curResultOdds = {
        0: curResultOdds[2],
        1: curResultOdds[1],
        2: curResultOdds[0],
        3: curResultOdds[3],
        4: curResultOdds[7],
        5: curResultOdds[6],
        6: curResultOdds[5],
        7: curResultOdds[4],
        8: curResultOdds[8]
    };

    // log('当前的结果：', curCardsStr);


    // 改变结果字符串
    curCardsStr = curCardsStr
        .replace(/庄/g, 'a')
        .replace(/闲/g, 'b')
        .replace(/a/g, '闲')
        .replace(/b/g, '庄');

    // log('改变后：', curCardsStr);

    obj.curCardsStr = curCardsStr;

    log(obj);

    for (var k in obj) {
        room[k] = obj[k];
    }
};

// 检查金钱数是否足够坐庄
PlayerManager.prototype.checkApplyBanker = function (playerId) {
    var players = this.playerData;
    var coin = players[playerId].coin;
    return coin > consts.ROOM.MIN_BANKER_COIN;
};

// 添加一定数量的robot到 playerData里面
PlayerManager.prototype.addRobot2PlayerData = function (num) {
    console.log('PlayerManager.prototype.addRobot caught >>>>>>>>>>>>>>>>>>>');

    var data = this.genRobot(num);

    // var playerId = data.playerId;

    for (var playerId in data) {

        // 检查是否已经有此ID
        if (this.playerData[playerId]) {
            log('机器人id 和已存在id 冲突了');
            continue;
        }

        this.playerData[playerId] = data[playerId];
        this.robotNum++;
        this.playerNum++;
        this.robotList.push(playerId);  // 都是放到队尾了  // 删除就用shift

        var ret = {
            playerId,
            name: data[playerId].playerName,
            coin: data[playerId].coin,
            score: data[playerId].score,
            roundCount: data[playerId].roundCount
        };

        if (this.roomObj.channel) {
            // ret = { "name": "test", "coin": "6491651", "score": "11", "roundCount": "511", "playerId": 111 }
            this.roomObj.channel.pushMessage('onPlayerEnter', ret, null);
        }

        playerLogger('enter', ret);

    }

    console.log('addRobot success');
    // console.log(this.playerData);

    // var data = {
    //     playerId: 9990001,
    //     playerName: playerName,
    //     sid: 'connector-server-1',
    //     isRobot: true,
    //     coin: 32123,
    //     score: 12,
    //     roundCount: 20
    // };

};

// 生成robot数据
PlayerManager.prototype.genRobot = function (num) {
    console.log('生成机器人数据........................');
    var data = {};
    // var beginId = this.robotNum + consts.ROBOT.BEGIN_ID;  // 这样在删掉机器人的情况下不可用
    var playerId;
    // var len = this.robotList.length;
    // if (len == 0) {
    //     beginId = consts.ROBOT.BEGIN_ID;
    // } else {
    //     beginId = parseInt(this.robotList[len - 1]) + 1; // 最后一位的id加1
    // }

    var idList = this.genRobotIdNew(num);
    var room = this.roomObj;
    var robotSet = this.robotSet;

    // console.log('idList');
    // console.log(idList);

    // for (var i = 0; i < num; i++) {
    for (playerId of idList) {
        // playerId = beginId;

        data[playerId] = {};
        data[playerId].playerName = utils.genName();
        data[playerId].isRobot = true;
        data[playerId].coin = utils.genRandomNum(robotSet.minCoin, robotSet.maxCoin);
        // data[playerId].coin = 3999900;
        data[playerId].score = utils.genRandomNum(10, 1000);
        data[playerId].roundCount = 0;
    }

    return data;
};

/**
 * 随机生成机器人id
 */
PlayerManager.prototype.genRobotIdNew = function (num) {
    log('新生成机器人id');

    var playerData = this.playerData;

    var endId = 14000;

    // while(endId < (this.robotList.length + num) * 5) {
    //     log('预留id不够用了');
    //     endId *=2;
    // }

    var idList = [], id, count;
    for (var i = 0; i < num;) {
        id = utils.genRandomNum(10000, endId);
        if (!playerData[id]) {
            idList.push(id);
            i++;
        }
        count++;
        if (count > (num * 5)) {  // 限定最大值，防止出现死循环
            break;
        }
    }

    log(idList);

    return idList;
};

// 更新机器人局数，检查机器人信息
// 当机器人在线局数超过一定局数的时候，就随机下线
// 暂定为五局，并已1/5的概率下线
// 机器人数量不足时，慢慢补足
// 下线要多要快，上线要慢
PlayerManager.prototype.updateRobotRound = function () {
    log('更新机器人局数!');

    var robotList = this.robotList;
    var playerData = this.playerData;

    for (var k of robotList) {
        playerData[k].roundCount++;
        // log(playerData[k]);
    }
};

/**
 * 生成robot 的 playerId
 * in: type: 生成类型; num: 生成数量
 * out: 机器人ID数组
 */
PlayerManager.prototype.genRobotId = function (type, num) {
    console.log('开始生成机器人ID ..............');
    console.log(type, num);

    var idList = [];

    if (!num) {
        num = type;
        type = 'add';
    }  // 默认是添加机器人

    var idNum = consts.ROBOT.ID_NUM || 1000;  // 默认循环1000个ID

    var len = this.robotList.length;  // 当前机器人队列的长度

    var BEGIN_ID = consts.ROBOT.BEGIN_ID;  // 配置的机器人开始ID
    var END_ID = consts.ROBOT.END_ID;  // 配置的机器人结束ID

    // 当this.robotList = [] 的时候，不用默认值的话此两项为undefined
    var beginId = this.robotList[0] || BEGIN_ID;  // 机器人队列的第一个机器人
    var endId = this.robotList[len - 1] || BEGIN_ID;  // 最后一个机器人


    if ((len + num) >= (END_ID - BEGIN_ID + 1)) {
        return idList;  // 如果ID数量已经满了，就直接返回
    }

    var i = 0,  // 循环用
        leftNum = 0,  // 从开头算的ID数量 // 队列左边的
        rightNum = 0;  // 从结尾算的ID数量  // 右边的

    if (type === 'add') {  // 添加机器人
        if ((endId + num) <= END_ID) {
            rightNum = num;
        }
        else {
            rightNum = END_ID - endId;
            leftNum = num - rightNum;
        }
        for (; i++ < rightNum;) {
            idList.push(endId + i);  // 从队列的结尾加1，累加
        }
        for (i = 0; i < leftNum; i++) {
            idList.push(BEGIN_ID + i);  // 从ID池的开头
        }
    }
    else if (type === 'del') {  // 删除机器人
        if (len <= num) {  // 如果总数量还没有删除数量多，返回全部ID
            return this.robotList;
        }
        else {
            // 总数量超过了要删除的数量，一定能够获取到足够多的ID
            if (this.robotList.indexOf(END_ID) > -1) {
                // 如果已经用到了或者超过了最后一个ID
                if ((END_ID - beginId) > num) {
                    rightNum = num;  // 右边的就已经够用
                }
                else {
                    // 右边全删，左边删剩下的
                    rightNum = END_ID - beginId;
                    leftNum = num - rightNum;
                }
            }
            else {
                // 没有用到最后一个ID
                rightNum = num;  // 右边的够用。其实是中间的右边的
            }
            for (i = 0; i < rightNum; i++) {
                idList.push(beginId + i);  // 从队列的开头
            }
            for (i = 0; i < leftNum; i++) {
                idList.push(BEGIN_ID + i);  // 从ID池的开头
            }
        }
    }

    return idList;
};

// 机器人下注
// 全下对的
PlayerManager.prototype.robotBid = function () {

    console.log('PlayerManager.robotBid caught >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
    // return;

    var self = this;

    var room = this.roomObj;
    var robotBidCount = room.robotBidCount;

    // 暂时最多50个人下注    
    var bidNum = consts.ROOM.BID_ROBOT_NUM || 10;  // 下注的人数
    // bidNum = 50;
    var pos = consts.ROOM.ROBOT_BID_POS;

    var beginTime = consts.ROOM.ROBOT_BID_TIME_BEGIN;
    var endTime = consts.ROOM.ROBOT_BID_TIME_END;

    // 下注时间限制
    // if (self.roomObj.checkTime > beginTime || self.roomObj.checkTime < endTime) {
    //     return;
    // }

    // 机器人随机下注
    // 每次随机个数，并且从机器人列表中随机位置开始下注
    var tempBidData = this.roomObj.tempBidData;
    var bidData = this.bidData;

    // 随机生成下注的人数和序列号
    // 如果是id号也重复，需要注意取号时候的重复性和id号数组是引用类型数据
    // var robotNum = utils.genRandomNum(consts.ROBOT.MIN_BID_NUM, consts.ROBOT.MAX_BID_NUM);
    // var beginIdx = utils.genRandomNum(0, this.robotNum);
    // var bidRobotList = this.robotList.slice(beginIdx, beginIdx + bidNum);

    if (room.robotNum) {
        bidNum = room.robotNum;
    }    

    var beginIdx = 0;  // 从索引0开始
    var bidRobotList = this.robotList.slice(beginIdx, beginIdx + bidNum);

    log('机器人列表:', this.robotList.toString());
    log('下注机器人列表:', bidRobotList.toString());

    // console.log(bidRobotList);

    // 考虑筹码是否要随机下
    var jetton = {
        0: 100,
        1: 500,
        2: 1000,
        3: 10000,
        4: 50000,
        5: 100000,
        6: 500000
    };
    var jettonList = [100, 500, 1000, 10000, 50000, 100000, 500000];

    // 设置的下注开始和结束位置
    var idx1 = jettonList.indexOf(this.robotSet.minJetton);
    var idx2 = jettonList.indexOf(this.robotSet.maxJetton);
    // log('下注范围： ', idx1, idx2);

    var posOdds = this.getBidPos();  // 正确的位置 positiveOdds

    var posOddsLen = posOdds.length;

    var playerId;
    // var bidRobotNum = 10;  // 下注的机器人的数量
    var count = 0;
    var msg;
    for (var i in bidRobotList) {
        playerId = bidRobotList[i];
        
        // 如果这个机器人已经上庄了，就不能下注了
        if (playerId == room.curBanker) {
            continue;
        }

        // count++;
        // if (count >= bidNum) {
        //     break;
        // }

        // 每一秒每个机器人只有1/5的概率会下注
        // 暂时改为全都下注
        if (utils.probability(1, 5)) {
            continue;
        }

        // var jetCount = utils.genRandomNum(1, 3);
        // var num = utils.genRandomNum(0, 5);
        // var jetNum = jetton[num];

        // 全押对的  // 所有位置都下注
        var maxBidPos;
        tempBidData[playerId] = {};
        for (var k of posOdds) {
            // 按中的概率下注
            if (!utils.checkBid(k)) {
                continue;
            }

            msg = {};

            if (k === 0 || k === 2) {
                maxBidPos = 5;
            }
            else {
                maxBidPos = 2;
            }

            var jetCount = utils.genRandomNum(1, 3);  // 下的筹码个数
            var num = utils.genRandomNum(idx1, idx2);  // 下的筹码是第几个位置的
            var jetNum = jetton[num];  // 下单筹码是多少分

            // log('此次下注的筹码是：', jetNum, ' 索引是：', num);

            jetCount = 1;

            msg[k] = jetNum;

            if (!room.checkBid(msg, playerId)) {
                continue;
            }

            // 减掉机器人金钱
            self.playerData[playerId].coin -= jetNum * jetCount;

            tempBidData[playerId][k] = {};
            tempBidData[playerId][k][jetNum] = jetCount;
            if (!bidData[playerId]) {
                bidData[playerId] = {};
            }
            if (!bidData[playerId][k]) {
                bidData[playerId][k] = 0;
            }

            bidData[playerId][k] += (jetNum * jetCount);

            var BJL = consts.ODDS.BJL;
            var bOdds = {
                0: BJL.PLAYER_WIN,
                1: BJL.DRAW,
                2: BJL.BANKER_WIN,
                3: BJL.BIG,
                4: BJL.PLAYER_NATURE,
                5: BJL.PLAYER_PAIR,
                6: BJL.BANKER_PAIR,
                7: BJL.BANKER_NATURE,
                8: BJL.SMALL
            };

            if (!robotBidCount[k]) {
                robotBidCount[k] = 0;
            }

            robotBidCount[k] += (jetNum * jetCount * bOdds[k]);

            log('机器人：', playerId, '下注在：', k, '下注数目是：', jetNum);
            // log(robotBidCount);
            break;  // 每个机器人下完一注就结束
        }
    }
};

// 获取下注位置
PlayerManager.prototype.getBidPos = function () {
    log('获取下注位置');

    var pos = [];

    var self = this;
    var room = self.roomObj;

    var resultOdds = room.curResultOdds;

    for (var k in resultOdds) {
        if (resultOdds[k] > 0) {
            pos.push(k);
        }
    }

    // 下注位置设置
    // posOdds = [0, 1, 2, 3, 4, 5, 6, 7, 8];
    // 0闲 1和 2庄 3大 4闲天王 5闲对子 6庄对子 7庄天王 8小
    pos = [0, 2];

    if (room.config && room.config.ROBOT && room.config.ROBOT.BID_POS) {
        pos = room.config.ROBOT.BID_POS;
    }

    // log('下注位置：', pos);
    return pos;
};


// 机器人离开
PlayerManager.prototype.kickRobotFromPlayerData = function (num) {
    console.log('kickRobotFromPlayerData caught >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
    var room = this.roomObj;
    var len = this.robotNum;
    num = Math.min(num, len);  // 获取待删除数量和机器人总数的最小值

    // 下注时候不能离开 // 如果没有下注就可以离开。那要调整下注策略
    if (room.checkGameStatus('xiazhu') || room.checkGameStatus('kaipai')) {
        log('下注时间，不踢机器人！');
        return;
    }

    var kickList = this.robotList.slice(0, num);  // 不能在这里直接弄成移出队列，这里只能取待删除的队列

    num = kickList.length;

    console.log('踢掉机器人列表：', kickList.toString());
    console.log('机器人列表：', this.robotList.toString());

    for (var i = 0; i < num; i++) {
        var robotId = kickList[i];

        console.log(robotId);
        console.log(this.bidData);

        if (this.bidData[robotId]) {  // 如果下注了，不能踢掉
            console.log('没有踢掉机器人', robotId);
            continue;
        }

        this.kickRobotById(robotId);

        // // 玩家掉线通知(机器人)
        // var msg = { playerId: robotId };
        // room.channel.pushMessage('onPlayerLeave', msg, null);
        // playerLogger('leave', 'robot', msg);


        // delete this.playerData[robotId];
        // this.robotList.forEach(function (val, idx, arr) {
        //     if (val === robotId) {
        //         arr.splice(idx, 1);
        //         return;
        //     }
        // });  // 安全地删除一个机器人
        // console.log('删除了机器人: ' + robotId);
        // this.playerNum--;
        // this.robotNum--;

    }
    console.log('删除了机器人之后', this.playerNum, this.robotNum);

};

/**
 * 根据playerId删除机器人
 */
PlayerManager.prototype.kickRobotById = function (playerId) {
    log('PlayerManager 删除机器人 ', playerId);

    var room = this.roomObj;

    if (parseInt(room.curBanker) === parseInt(playerId)) {
        console.log('机器 %s 是当前的庄，不踢', playerId);
        return;
    }

    this.robotList.forEach(function (val, idx, arr) {
        if (val === playerId) {
            arr.splice(idx, 1);
        }
    });  // 安全地删除掉机器人  forEach不能 return和 break
    delete this.playerData[playerId];

    // 玩家掉线通知(机器人)
    var msg = { playerId };

    if (room.channel) {
        room.channel.pushMessage('onPlayerLeave', msg, null);
    }

    this.robotNum--;
    this.playerNum--;

    playerLogger('leave', msg);
};


/**
 * Expose 'playerManager' constructor.
 */
module.exports = PlayerManager;

